package com.starry.module.system.core.oauth2.authorization.grant;

import com.starry.core.common.constants.CommonConstant;
import com.starry.module.system.core.oauth2.authorization.constant.SecurityConstants;
import com.starry.module.system.core.oauth2.authorization.utils.SecurityUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 自定义Grant登录Token转换器
 *
 * @author 小柯
 */
public class CustomGrantGrantAuthenticationConverter implements AuthenticationConverter {

    static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";

    private static final Set<String> grantTypes = new HashSet<>(Arrays.asList(
            SecurityConstants.GRANT_TYPE_SMS_CODE,
            CommonConstant.INTERNAL_CLIENT_GRANT_TYPE,
            SecurityConstants.GRANT_TYPE_PASSWORD,
            SecurityConstants.GRANT_TYPE_THIRD
    ));

    @Override
    public Authentication convert(HttpServletRequest request) {

        // 判断是否是自定义授权类型
        String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
        if (!grantTypes.contains(grantType)) {
            return null;
        }

        // 这里目前是客户端认证信息
        Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
        // 获取请求中的参数
        MultiValueMap<String, String> Schemas = SecurityUtils.getSchemas(request);

        String scope = Schemas.getFirst(OAuth2ParameterNames.SCOPE);
        if (StringUtils.hasText(scope) &&
                Schemas.get(OAuth2ParameterNames.SCOPE).size() != 1) {
            SecurityUtils.throwError(
                    OAuth2ErrorCodes.INVALID_REQUEST,
                    "SCOPE不存在",
                    ACCESS_TOKEN_REQUEST_ERROR_URI);
        }

        Set<String> requestedScopes = null;
        if (StringUtils.hasText(scope)) {
            requestedScopes = new HashSet<>(
                    Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
        }
        // 短信验证参数
        if (SecurityConstants.GRANT_TYPE_SMS_CODE.equals(grantType)) {
            checksCaptchaGrantSchemas(request, Schemas);
        }

        // 提取附加参数
        Map<String, Object> additionalSchemas = new HashMap<>();
        Schemas.forEach((key, value) -> {
            if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
                    !key.equals(OAuth2ParameterNames.CLIENT_ID)) {
                additionalSchemas.put(key, value.get(0));
            }
        });

        // 构建AbstractAuthenticationToken子类实例并返回
        return new CustomGrantAuthenticationToken(new AuthorizationGrantType(grantType), clientPrincipal, requestedScopes, additionalSchemas);
    }


    private void checksCaptchaGrantSchemas(HttpServletRequest request, MultiValueMap<String, String> Schemas) {

        // 校验手机号码和验证码
        String username = Schemas.getFirst(SecurityConstants.OAUTH_SCHEMA_NAME_PHONE);
        if (!StringUtils.hasText(username) || Schemas.get(SecurityConstants.OAUTH_SCHEMA_NAME_PHONE).size() != 1) {
            SecurityUtils.throwError(
                    OAuth2ErrorCodes.INVALID_REQUEST,
                    "手机号码不能为空",
                    ACCESS_TOKEN_REQUEST_ERROR_URI);
        }

        String code = Schemas.getFirst(SecurityConstants.OAUTH_Schema_NAME_SMS_CAPTCHA);
        if (!StringUtils.hasText(code) || Schemas.get(SecurityConstants.OAUTH_Schema_NAME_SMS_CAPTCHA).size() != 1) {
            SecurityUtils.throwError(
                    OAuth2ErrorCodes.INVALID_REQUEST,
                    "验证码不能为空",
                    ACCESS_TOKEN_REQUEST_ERROR_URI);
        }
    }

}
